package com.li.service.impl;
import cn.hutool.core.util.IdUtil;
import com.li.service.RedisLock01Service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;
//v3.0

/**
 *根据v2.0的代码:
 * 1.使用while 循环判断，防止线程虚假唤醒
 * 2.使用while 循环代替递归
 * 3.加入超时释放锁，防止死锁
 * 此时问题:
 * 1. stringRedisTemplate.delete(key);只能自己删除自己的锁，不可以删除别人的
 * 2. 为了保证redis命令的原子性 ,todo(2) 处应该为一行 ;同理 todo(1)出加了判断 也应该为1行
 */
@Slf4j
@Service
public class RedisLock01ServiceImpl3 implements RedisLock01Service {
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Value("${server.port}")
    private String port;

    @Override
    public String sale() {
        String retMessage = "";
        String key = "redisLock";
        String uuidValue = IdUtil.simpleUUID() + ":" + Thread.currentThread().getId();
        Boolean flag = redisTemplate.opsForValue().setIfAbsent(key, uuidValue,20, TimeUnit.MILLISECONDS);//todo(2) todo(2)处应该为一行
        while (!flag) { //todo(2)
            try {
                TimeUnit.MILLISECONDS.sleep(20);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            flag = redisTemplate.opsForValue().setIfAbsent(key, uuidValue, 20, TimeUnit.MILLISECONDS);//todo(2)
        }
        try {
            //查询库存信息
            String result = redisTemplate.opsForValue().get("inventory");
            //判断库存是否足够
            Integer inventoryNum = result == null ? 0 : Integer.parseInt(result);
            if (inventoryNum > 0) {
                redisTemplate.opsForValue().set("inventory", String.valueOf(inventoryNum - 1));
                retMessage = "成功售出商品，当前库存为：" + redisTemplate.opsForValue().get("inventory") + "，购买端口为：" + port;
                System.out.println(retMessage);
            } else {
                retMessage = "库存不足，当前库存为：" + redisTemplate.opsForValue().get("inventory") + "，购买端口为：" + port;
                System.out.println(retMessage);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            redisTemplate.delete(key);//todo (1) 假设线程A拿到锁后一直在业务模块卡住 ,一直到锁失效 ,线程B执行这条语句就是删除线程A的锁
        }
        return retMessage;

    }

}
